//////////////////////////////////////////////////////////////////////////////
//
//  Created by Philip Mulcahy on 02/03/2013.
//  Copyright (c) 2013 Philip Mulcahy. All rights reserved.
//
//  This file is part of the note-recog library.
//
//  note-recog is free software: you can redistribute it and/or modify
//  it under the terms of version 3 of the GNU Lesser General Public License 
//  as published by the Free Software Foundation.
//
//  note-recog is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with note-recog. If not, see <http://www.gnu.org/licenses/>.
//
//////////////////////////////////////////////////////////////////////////////


#include "TimeDomainGenerator.h"
#include "FrameGenParam.h"
#include "IFrameGenParamGen.h"
#include <cmath>


const float  TWO_PI = std::atan(1.0)*8;


TimeDomainGenerator::TimeDomainGenerator(IFrameGenParamGen& gen,
                                       float samplingFreq,
                                       float frameSize)
: _sequenceNumber(0),
  _gen(gen),
  _frameInterval(frameSize/samplingFreq),
  _samplingFreq(samplingFreq),
  _sampleInterval(1.f/samplingFreq),
  _frameSize(frameSize)
{}


TimeDomainGenerator::~TimeDomainGenerator()
{}


std::pair<float, std::vector<short> > TimeDomainGenerator::next()
{
    const float t_start = timeStamp();
    const std::vector<FrameGenParam> params = _gen.getComponentParams(t_start);
    ++_sequenceNumber;
    std::vector<short> vec;
    for(size_t i=0; i!=_frameSize; ++i) {
        vec.push_back(0);
        const float t = t_start + i * _sampleInterval;
        
        // Each param represents a note, each of which could be contributing
        // to this frame.
        for(const FrameGenParam& param : params)
        {
            const float omega = TWO_PI * param.frequency();
            const float val = param.amplitude() *
                              exp((t_start-t)/param.lambda()) *
                              sin(omega * t);
            const short short_val = static_cast<short>(val);
            *(vec.rbegin()) += short_val;
        }
    }
    return std::pair<float, std::vector<short> >(t_start, vec);
}


float TimeDomainGenerator::timeStamp() const
{
    return  _sequenceNumber * _frameInterval;
}


bool TimeDomainGenerator::hasNext() const
{
    const float t = timeStamp();
    const float d = _gen.duration();
    return t < d;
}